/*
 * @Author: 鱿鱼溪学院
 * @Date: 2025-04-19 18:04:24
 * @LastEditTime: 2025-07-08 23:32:12
 * @LastEditors: 鱿鱼溪学院
 * @Description:
 * @FilePath: \yyx_ser_ts\app\controller\UserController.ts
 * Copyright 鱿鱼溪学院 by edu v1.0
 * 天道酬勤
 */
import { Context, Next } from 'koa'
import response from '../../utils/response'
import { MethodName } from '../router/decorator/type'
import {
  get,
  post,
  patch,
  controller,
  use,
  unifyUse
} from '../router/decorator/index'
import AdminService from '../service/AdminService'
import {
  userValidator,
  crpytPassword,
  verifyUser,
  verifyLogin,
  verifyPhone,
  decryptMiddleware,
  verifyVerificationCode
} from '../middleware/UserMiddleware'
import config from '../config'
import jwt from 'jsonwebtoken'
import {
  GetAdminException,
  PasswordValidationException,
  UserValidationException
} from '../exception/HttpException'
import { authToken } from '../middleware/AuthMiddleware'
import bcrypt from 'bcryptjs'
import UserService from '../service/UserService'
import { generateRandomUsername, hashPassword } from '../../utils/user'

//管理员管理控制器
@controller('/user')
@unifyUse<MethodName>(decryptMiddleware, ['changePassword', 'getUserInfoById'])
class UserController {
  //用户注册接口
  @post('/register')
  @use(crpytPassword)
  @use(verifyPhone)
  @use(verifyUser)
  async register(ctx: Context) {
    const {
      decryptedUsername: username,
      decryptedPassword: password,
      decryptedPhone: phone
    } = ctx.state

    console.log(ctx.state, username, password, phone)
    //    return
    try {
      const res = await UserService.createUser(username, password, phone)
      console.log(res, 'res')
      if (res) {
        response.success(ctx, res, '用户注册成功！')
      }
    } catch (err) {
      throw new UserValidationException(err, '用户已存在！')
    }
    // const res = await UserService.createUser(username, password)
    // response.success(ctx, res, '用户注册成功！')
  }

  //手机注册接口
  @post('/phoneRegister')
  @use(verifyVerificationCode)
  @use(verifyPhone)
  async phoneRegister(ctx: Context) {
    // 1. 获取请求体中的手机号和验证码
    const { decryptedPhone } = ctx.state

    console.log(ctx.state, 'ctx.state')
    console.log(
      decryptedPhone,
      '手机号和验证码均已通过验证，进入注册环节！！！！'
    )

    if (!decryptedPhone) {
      throw new UserValidationException(null, '手机号不能为空')
    }

    let username

    let isUsernameUnique = false

    // 循环生成随机用户名，直到找到唯一的用户名
    while (!isUsernameUnique) {
      // 生成随机用户名
      username = generateRandomUsername()

      console.log(username, '用户名已生成！')
      try {
        const existingUser = await UserService.getUserInfo({ username })
        if (!existingUser) {
          isUsernameUnique = true
        }
      } catch (error) {
        throw new UserValidationException(error, '检查用户名唯一性时出错！')
      }
    }

    // 生成一个临时密码，这里简单使用手机号后 6 位
    const password = decryptedPhone.slice(-6)

    const hashedPassword = hashPassword(password) // 修改变量名为 hashedPassword

    console.log(hashPassword, '加密后的password')

    // return response.success(
    //   ctx,
    //   { username, password, decryptedPhone },
    //   '手机注册成功！'
    // )

    try {
      // 调用注册接口
      const res = await UserService.createUser(
        username!,
        hashedPassword as string,
        decryptedPhone
      )
      console.log(res, 'res')
      if (res) {
        response.success(ctx, res, '用户注册成功！')
      }
    } catch (err) {
      throw new UserValidationException(err, '用户注册失败！')
    }
  }

  //用户登录接口
  @post('/login')
  @use(verifyLogin)
  async login(ctx: Context) {
    const { username } = ctx.request.body

    response.success(ctx, { username }, '用户登录成功！')

    //1.获取用户信息
    try {
      const result = await AdminService.getAdminInfo({ username })
      //从返回结果对象中剔除password属性，将剩下的属性放到新的对象中
      const { password, ...res } = result

      const JWT_SECRET = config.jwt.jwt_secret
      //拼接token
      let token = jwt.sign(res, JWT_SECRET as string, { expiresIn: '2.5h' })
      //{token} 相当于{ token: token }
      response.success(ctx, { token }, '用户登录成功！')
    } catch (err) {
      throw new UserValidationException(err, '用户登录失败！', 400)
    }
  }

  // 手机登录接口
  @post('/phoneLogin')
  @use(verifyVerificationCode)
  @use(verifyPhone)
  async phoneLogin(ctx: Context) {
    const { decryptedPhone } = ctx.state

    if (!decryptedPhone) {
      throw new UserValidationException(null, '手机号不能为空')
    }

    try {
      // 根据手机号查询用户信息
      const user = await UserService.getUserInfo({ phone: decryptedPhone })

      if (!user) {
        throw new UserValidationException(null, '用户不存在，请先注册')
      }

      const JWT_SECRET = config.jwt.jwt_secret
      // 生成 token，这里可以根据需求添加更多用户信息到 token 中
      const token = jwt.sign(
        { userId: user.id, phone: user.phone },
        JWT_SECRET as string,
        { expiresIn: '2.5h' }
      )

      response.success(ctx, { token }, '手机登录成功！')
    } catch (err) {
      throw new UserValidationException(err, '手机登录失败！')
    }
  }

  // ... existing code ...

  // 无需验证的手机登录接口
  @post('/phoneLoginWithoutVerification')
  async phoneLoginWithoutVerification(ctx: Context) {
    const { decryptedPhone } = ctx.state
    console.log(decryptedPhone, 'phone.......')

    console.log(ctx.state, 'ctx.state')

    if (!decryptedPhone) {
      throw new UserValidationException(null, '手机号不能为空')
    }

    try {
      // 根据手机号查询用户信息
      const user = await UserService.getUserInfo({ phone: decryptedPhone })

      if (!user) {
        throw new UserValidationException(null, '用户不存在，请先注册')
      }

      const JWT_SECRET = config.jwt.jwt_secret
      // 生成 token，这里可以根据需求添加更多用户信息到 token 中
      const token = jwt.sign(
        { userId: user.id, phone: user.phone },
        JWT_SECRET as string,
        { expiresIn: '2.5h' }
      )

      response.success(ctx, { token }, '手机登录成功！')
    } catch (err) {
      throw new UserValidationException(err, '手机登录失败！')
    }
  }

  //通过token获取用户信息接口

  @get('/user')
  @use(authToken)
  async getUserInfoById(ctx: Context) {
    try {
      const { id } = ctx.state.user
      //把字符串类型转换为数字类型
      let userId = Number(id)
      console.log(userId, 'userId')
      //根据id查询用户信息
      const user = await UserService.getUserInfo({ id: userId })
      if (!user) {
        throw new UserValidationException(null, '用户不存在')
      }
      response.success(ctx, user, '获取用户信息成功')
    } catch (err) {
      throw new UserValidationException(err, '获取用户信息失败')
    }
  }

  //修改密码接口
  @patch('/')
  @use(crpytPassword)
  @use(authToken)
  async changePassword(ctx: Context) {
    // 1.获取数据
    //  id为state的数据，因为在解析token时，user数据被写在ctx.state中
    const id = ctx.state.user.id
    console.log(id)
    // newpassword为
    const password = ctx.request.body.password
    const username = ctx.state.user.username
    console.log(password, '要修改的密码！')
    //2.操作数据库
    try {
      const res1 = await AdminService.getAdminInfo({ username })

      console.log(res1.password, '数据库中的密码')

      if (!res1) {
        return response.failResponse(ctx, '用户不存在！', username)
      }

      if (bcrypt.compareSync(password, res1.password)) {
        throw new PasswordValidationException('', '新密码和旧密码相同！')
      }

      const res2 = await AdminService.updateById({ id, username, password })

      if (res2) {
        response.success(ctx, res2, '密码修改成功！')
      }
    } catch (err) {
      throw new PasswordValidationException(err, '密码修改失败！')
    }

    // try {
    //   const res = await getUserInfo({ username })
    //   if (bcrypt.compareSync(newPassword, res.password)) {
    //     ctx.app.emit('error', samePassword, ctx)
    //     return
    //   }

    //   //加盐
    //   const salt = bcrypt.genSaltSync(10)
    //   //hash保存的是密文
    //   const hash = bcrypt.hashSync(newPassword, salt)
    //   const password = hash

    //   //2.操作数据库
    //   if (await updateById({ id, password })) {
    //     ctx.body = {
    //       code: 0,
    //       message: '修改密码成功！',
    //       data: ''
    //     }
    //   }
    // } catch (err) {
    //   console.log('修改密码失败')
    //   ctx.app.emit('error', changePassword, ctx)
    // }
  }

  //获取用户信息接口
  @get('/getUserInoById')
  //@use(authToken)
  async getUserInoById(ctx: Context) {
    try {
      const { id } = ctx.state.user
      //把字符串类型转换为数字类型
      let userId = Number(id)
      console.log(userId, 'userId')
      const res = await AdminService.findUserInfoById(userId)
      response.success(ctx, res, '通过ID获取用户信息成功！')
    } catch (error: any) {
      throw new GetAdminException(error, error.messages)
    }
  }
}

export default new UserController()
